Swadhin Biswas Feature/ai code reviewer (#73) · 8/2/2026
105a287
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import type { APIRoute } from "astro";
import { handleReceivePack } from "@/lib/git-server";
import { acquireRepo, releaseRepo, getStorageRepoPath } from "@/lib/git-storage";
import { logger } from "@/lib/logger";
import { getDatabase, schema } from "@/db";
import { validateBasicAuth } from "@/lib/auth-basic";
import { canWriteRepo } from "@/lib/permissions";
import { and, eq } from "drizzle-orm";
export const POST: APIRoute = async ({ params, request }) => {
const { owner, repo } = params;
if (!owner || !repo) {
return new Response("Missing owner or repo", { status: 400 });
}
// Handle .git suffix
const repoName = repo.endsWith(".git") ? repo.slice(0, -4) : repo;
// Check Content-Type
const contentType = request.headers.get("Content-Type");
if (contentType !== "application/x-git-receive-pack-request") {
return new Response("Invalid Content-Type", { status: 415 });
}
// Authenticate user
const authHeader = request.headers.get("Authorization");
let userId: string | null = null;
if (authHeader) {
userId = await validateBasicAuth(authHeader);
}
// Find repo and check permissions
const db = getDatabase();
const ownerUser = await db.query.users.findFirst({
where: eq(schema.users.username, owner),
});
if (!ownerUser) {
return new Response("Repository not found", { status: 404 });
}
const repoData = await db.query.repositories.findFirst({
where: and(
eq(schema.repositories.ownerId, ownerUser.id),
eq(schema.repositories.name, repoName)
),
});
if (!repoData) {
return new Response("Repository not found", { status: 404 });
}
// Check write permission
const user = userId ? await db.query.users.findFirst({
where: eq(schema.users.id, userId),
}) : null;
const isAdmin = user?.isAdmin === true;
const hasAccess = await canWriteRepo(userId || undefined, repoData, { isAdmin });
if (!hasAccess) {
return new Response("Unauthorized", {
status: 401,
headers: { "WWW-Authenticate": 'Basic realm="OpenCodeHub"' },
});
}
logger.info({ owner, repoName }, "Git receive-pack request");
let repoPath: string;
try {
repoPath = await acquireRepo(owner, repoName);
} catch (err) {
logger.error({ err }, "Failed to acquire repo");
return new Response("Repository not found", { status: 404 });
}
const storagePath = getStorageRepoPath(owner, repoName);
// Extract user from Basic Auth if present
let remoteUser = "git";
if (authHeader && authHeader.startsWith("Basic ")) {
try {
const buffer = Buffer.from(authHeader.slice(6), "base64");
const creds = buffer.toString("utf-8");
const [user] = creds.split(":");
if (user) remoteUser = user;
} catch (e) {
// Ignore auth parse errors
}
}
try {
// Process the pack stream
const responseStream = await handleReceivePack(repoPath, request.body!, storagePath, {
REMOTE_USER: remoteUser
});
// Return response first, then sync to cloud storage in background
// This prevents the S3 upload from blocking the git client response
const response = new Response(responseStream as any, {
headers: {
"Content-Type": "application/x-git-receive-pack-result",
"Cache-Control": "no-cache",
},
});
// Sync to cloud storage in background (non-blocking)
releaseRepo(owner, repoName, true).catch(err => {
logger.error({ err }, "Failed to sync repo to storage after push");
});
return response;
} catch (err) {
logger.error({ err }, "Failed to handle receive-pack");
// Release repo without saving changes (rollback attempt)
await releaseRepo(owner, repoName, false);
return new Response("Internal Server Error", { status: 500 });
}
};